

//?? vector<float, AllocatorPoolBased<int,500>> vec2(100,0.0);

#ifndef ALLOCATORPOOLBASED_H
#define	ALLOCATORPOOLBASED_H

#include <memory>


#include <boost/scoped_array.hpp>
#include <boost/assert.hpp>


using boost::scoped_array;

using std::size_t;
using std::ptrdiff_t;


#include "Debugging.h"

/*
 Pool based allocator
 */
  template<typename _Tp>
    class AllocatorPoolBased
    {
    public:

      unsigned int _PoolSize;

      typedef size_t     size_type;
      typedef ptrdiff_t  difference_type;
      typedef _Tp*       pointer;
      typedef const _Tp* const_pointer;
      typedef _Tp&       reference;
      typedef const _Tp& const_reference;
      typedef _Tp        value_type;

      

     


      template<typename _Tp1>
        struct rebind
        { typedef AllocatorPoolBased<_Tp1> other; };

      AllocatorPoolBased(unsigned int __PoolSize=100) throw()
              :_PoolSize(__PoolSize)
      {
          init();
      }

      //AllocatorPoolBased(const AllocatorPoolBased&) throw() { }

      //template<typename _Tp1>
      //  AllocatorPoolBased(const AllocatorPoolBased<_Tp1>&) throw() { }

      //template <class U>
      //AllocatorPoolBased& operator=(const AllocatorPoolBased<U>&) throw();

      ~AllocatorPoolBased() throw() { }

      pointer
      address(reference __x) const { return &__x; }

      const_pointer
      address(const_reference __x) const { return &__x; }

      // NB: __n is permitted to be 0.  The C++ standard says nothing
      // about what the return value is when __n == 0.
      pointer
      allocate(size_type __n, const void* = 0)
      {
	if (__n > this->max_size())
	  std::__throw_bad_alloc();

	return instance();
      }

      // __p is not permitted to be a null pointer.
      void
      deallocate(pointer __p, size_type)
      { 
          freeInstance(__p);
      }

      size_type
      max_size() const throw()
      { return 1; }

      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // 402. wrong new expression in [some_] allocator::construct
      void
      construct(pointer __p, const _Tp& __val)
      { ::new((void *)__p) _Tp(__val); }


      void
      destroy(pointer __p) { __p->~_Tp(); }


    private:

        AllocatorPoolBased(AllocatorPoolBased&){};
        AllocatorPoolBased& operator=(AllocatorPoolBased&){};

        scoped_array<_Tp> poolOfObjects;
        scoped_array<_Tp*> freeObjectsInPool;
        int freeObjectsInPoolTop;

        void init()
        {
            BOOST_ASSERT_MSG(_PoolSize>0,"invalid template parameter _PoolSize");

            poolOfObjects.reset(new _Tp[_PoolSize]);
            freeObjectsInPool.reset(new _Tp*[_PoolSize]);


            BOOST_ASSERT_MSG(poolOfObjects.get()!=NULL,"cant allocate memory");
            BOOST_ASSERT_MSG(freeObjectsInPool.get()!=NULL,"cant allocate memory");

            freeAll();
        }


        void freeAll()
        {
            for(freeObjectsInPoolTop=0;freeObjectsInPoolTop<_PoolSize;freeObjectsInPoolTop++)
            {
                freeObjectsInPool[freeObjectsInPoolTop]=&poolOfObjects[freeObjectsInPoolTop];
            }
        }


        _Tp* instance()
        {
            BOOST_ASSERT_MSG(freeObjectsInPoolTop>0,"cant allocate memory");
            
            return freeObjectsInPool[--freeObjectsInPoolTop];
        }

        void freeInstance(_Tp* pointer)
        {
            BOOST_ASSERT_MSG(pointer>=&poolOfObjects[0]&&pointer<=&poolOfObjects[_PoolSize-1],"pointer outside the pool");
            BOOST_ASSERT_MSG(freeObjectsInPoolTop<=_PoolSize,"you have freed at least one instance more than once");

            ONLY_WHEN_DEBUGGING(\
             for(int i=0;i<freeObjectsInPoolTop;i++)\
                BOOST_ASSERT_MSG(pointer<freeObjectsInPool[i]||pointer>=freeObjectsInPool[i]+1,"not a valid pool pointer");\
            )

//           ONLY_WHEN_DEBUGGING(\
//             for(int i=0;i<freeObjectsInPoolTop;i++)\
//                BOOST_ASSERT_MSG(pointer!=freeObjectsInPool[i],"not a valid pool pointer");\
//            )

            freeObjectsInPool[freeObjectsInPoolTop++]=pointer;
        }

    };

  template<typename _Tp>
    inline bool
    operator==(const AllocatorPoolBased<_Tp>&, const AllocatorPoolBased<_Tp>&)
    { return true; }
  
  template<typename _Tp>
    inline bool
    operator!=(const AllocatorPoolBased<_Tp>&, const AllocatorPoolBased<_Tp>&)
    { return false; }

#endif	/* AllocatorPoolBased_H */

